use std::sync::Once;

use build_time::build_time_local;
use log;
use tracing;
use tracing_subscriber;
// use tracing_subscriber::prelude::*;
use version::version;

pub static GLOBAL_LOG_ONCE: Once = Once::new();

// logging init android
#[cfg(target_os = "android")]
fn logging(app_tag: &str, log_level: &str) {
    use android_logger::Config;
    use log::Level;
    android_logger::init_once(
        Config::default()
            .with_filter(
                android_logger::FilterBuilder::new()
                    .parse(&format!("{}", log_level))
                    .build(),
            )
            .with_min_level(log_level_from_str(log_level))
            .with_tag(app_tag),
    );
}

// logging init platform,tracing
#[cfg(all(not(target_os = "android")))]
fn logging(_app_tag: &str, log_level: &str) {
    let _collector = tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or(
                tracing_subscriber::EnvFilter::new(&format!("{}", log_level)),
            ),
        )
        .init();
}

// setup hook panic and tracing
pub fn setup_logger(app_tag: &str, log_level: &str) {
    logging(app_tag, log_level);
    std::panic::set_hook(Box::new(|panic| {
        if let Some(location) = panic.location() {
            // On nightly Rust, where the `PanicInfo` type also exposes a
            // `message()` method returning just the message, we could record
            // just the message instead of the entire `fmt::Display`
            // implementation, avoiding the duplciated location
            tracing::error!(
                message = %panic,
                panic.file = location.file(),
                panic.line = location.line(),
                panic.column = location.column(),
            );
        } else {
            tracing::error!(message = %panic);
        }
    }));
}

////////////////////////////////
///  global log init
///  adapt android and ios and linux and harmonyos?
////////////////////////////////
pub fn global_log_init(app_tag: &str, log_level: &str) {
    GLOBAL_LOG_ONCE.call_once(|| {
        setup_logger(app_tag, log_level);
        let local_build_time = build_time_local!("%Y-%m-%d %H:%M:%S");
        let version = version!();

        log::warn!(
            "app_tag: {} version: {} build_time: {}",
            app_tag,
            version,
            local_build_time
        );
    });
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_logutil_helloworld() {
        use crate::utils::logutil;
        logutil::global_log_init("coolink", "WARN");

        log::error!("log error: hello world!");
        log::warn!("log warning: hello world!");
        log::info!("log info: hello world!");
        log::debug!("log debug: hello world!");
        log::trace!("log trace: hello world!");
    }
}
